Eléments de programmation

Pour mener à bien un calcul algorithmique le nombre d'éléments de langage n'est pas très important et peut se résumer aux 3 syntaxes suivantes

  • Le choix conditionnel if-elseif-else-end.
  • La boucle for-end.
  • La boucle while-end

if ... elseif ... else ... end

Un choix simple si le test est vrai (k==1) alors le bloc d'instruction est évalué


In [1]:
k=1;
if k==1
    println("k=1")
end


k=1

Le else permet de donner un résultat par défaut...


In [2]:
k=1;
if k!=1
    println("k<>1")
else
    println("k=1")
end


k=1

Une succession de elseif permet de choisir parmi plusieurs critères, dans la succession des bloks de if et elseif le premier qui est "vrai" est évaluer et l'instruction s'arrète.


In [3]:
k=2;
if k==1
    println("k=1")
elseif k>1
    println("k>1")
else 
    println("k<1")
end


k>1

La boucle for

Elle peut se définir à l'aide d'itérateurs ou de tableaux de valeurs les syntaxes "=" ou "in" sont équivallentes


In [4]:
for i=1:10
    println(i)
end


1
2
3
4
5
6
7
8
9
10

In [5]:
for i in ["un" 2 im]
    println(typeof(i))
end


ASCIIString
Int64
Complex{Bool}

La commande breack permet de sortir d'une boucle à tout moment


In [6]:
for i = 1:1000
    println(i)
    if i >= 5
       break
    end
end


1
2
3
4
5

La commande continue permet elle de courtcircuiter la boucle en court et de passer à la valeur suivante


In [7]:
for i = 1:10
    if i % 3 != 0 # i modulo 3 different de 0
        continue
    end
    println(i)
end


3
6
9

La boucle while

Tant que le test est "vrai" le blok est évalué, le test se faisant en entrée de blok


In [8]:
k=0;
while k<10
    k+=1  # k=k+1
    println(k)
end


1
2
3
4
5
6
7
8
9
10

De même que la boucle for les commandes breack et continue sont valable...


In [9]:
k=0;
while k<1000
    k+=1  # k=k+1
    if k % 5 != 0 # k modulo 5 different de 0
        continue # retour en début de boucle avec de nouveau un test sur k
    end
    println(k)
    if k>30
        break
    end
end


5
10
15
20
25
30
35

Un peu d'optimisation

JULIA est dit un langage performant, regardons rapidement quelques exemples à faire ou ne pas faire.

Exemple de préallocation et utilisation de push!


In [10]:
tic()
A=[];
for i=1:10000
    A=[A,i];   # a chaque itération on change la taille de A
end
toc()


elapsed time: 0.694562798 seconds
Out[10]:
0.694562798

In [11]:
tic()
A=zeros(0);
for i=1:10000
    push!(A,i);   # a chaque itération on change la taille de A
end
toc()


elapsed time: 0.008444079 seconds
Out[11]:
0.008444079

In [12]:
tic()
A=zeros(10000)
for i=1:10000
    A[i]=i;
end
toc()


elapsed time: 0.0064525 seconds
Out[12]:
0.0064525

Cet exemple montre le coût prohibitif d'une réallocation dynamique qui impose une recopie totale de A à chaque itération.

Exemple de vectorisation

Regardons la vectorisation sous JULIA à l'aide de la construction d'une matrice de Vandermond


In [13]:
tic()
n=3000;
x=linspace(0,1,n);
V=zeros(n,n);
for i=1:n
    V[:,i]=x.^(i-1) # calcul vectorisé
end
toc()


elapsed time: 0.480871367 seconds
Out[13]:
0.480871367

In [14]:
tic()
n=3000;
x=linspace(0,1,n);
X=zeros(n,n);
for i=1:n
    for j=1:n
        X[i,j]=x[i]^(j-1) # calcul dévectorisé
    end
end
toc()


elapsed time: 4.19758533 seconds
Out[14]:
4.19758533

In [15]:
tic()
n=3000;
x=linspace(0,1,n);
W=[x[i]^(j-1) for i=1:n, j=1:n];
toc()


elapsed time: 10.599567818 seconds
Out[15]:
10.599567818

In [16]:
function Vander(n)
    x=linspace(0,1,n);
    V=zeros(n,n);
    for i=1:n
        for j=1:n
            V[i,j]=x[i]^(j-1) # calcul dévectorisé
        end
    end
end
tic(); Z=Vander(3000); toc()


elapsed time: 0.615316079 seconds
Out[16]:
0.615316079

La conclusion n'est pas très évidante... Néanmoins on peut voir que le fait de mettre le code dans une fonction impose une optimisation à la compilation...